package com.kb.medical.service.es;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kb.medical.config.ESClient;
import com.kb.medical.entity.Es;
import com.kb.medical.entity.EsStar;
import com.kb.medical.mapper.mp.EsMapper;
import com.kb.medical.mapper.mp.FileMapper;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.collapse.CollapseBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class EsServiceImpl implements EsService {
    @Autowired
    RestHighLevelClient client = ESClient.getClient();
    @Autowired
    private EsMapper esMapper;
    @Autowired
    private FileMapper fileMapper;

    @Override
    public List<Es> search(String searchKey, int userId) {
        String tableName = "search_" + userId;
        if (esMapper.isExitsTable(tableName) == 0) {
            esMapper.createSearchTable(tableName);
        }

        SearchRequest searchRequest = new SearchRequest("pdftxt,image");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        MultiMatchQueryBuilder multiMatchQuery = QueryBuilders.multiMatchQuery(searchKey, "ocrText", "pdfText");

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery().must(multiMatchQuery);

        sourceBuilder.query(boolQuery);

        HighlightBuilder highlightBuilder = new HighlightBuilder()
                .field("ocrText")
                .field("pdfText")
                .preTags("<mark style='color:red'>")
                .postTags("</mark>")
                .fragmentSize(50);


        sourceBuilder.highlighter(highlightBuilder);
        //获取条数
        sourceBuilder.size(120);
        sourceBuilder.timeout(TimeValue.timeValueSeconds(10));
        //去重根据id折叠
        sourceBuilder.collapse(new CollapseBuilder("id"));
        searchRequest.source(sourceBuilder);

        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
//        System.out.println(searchResponse);


        ObjectMapper objectMapper = new ObjectMapper();


// 处理查询结果
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            Es es = new Es();
            // 获取原始文档
            String sourceAsString = hit.getSourceAsString();
//            System.out.println("Source: " + sourceAsString);

            JsonNode jsonNode = null;
            try {
                jsonNode = objectMapper.readTree(sourceAsString);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
            // 获取高亮的片段
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();


            HighlightField pdfTextHighlightField = highlightFields.get("pdfText");
            HighlightField ocrTextHighlightField = highlightFields.get("ocrText");

            //计算最终评分
            DecimalFormat df = new DecimalFormat();
            df.setMinimumFractionDigits(1);
            int like = jsonNode.path("like").asInt();
            int click = jsonNode.path("click").asInt();
            float oldRelativeScore = hit.getScore();
            float relativeScore = Float.parseFloat(df.format(oldRelativeScore));

            double oldScore = relativeScore * 0.6 + like * 0.3 + click * 0.1;
            float score = Float.parseFloat((df.format(oldScore)));

            //检查该数据是否已收藏
            es.setStar(showIsStar(userId, jsonNode.path("id").asInt(), searchKey));

            //注入到对象
            es.setId(jsonNode.path("id").asInt());
//            es.setPath(jsonNode.path("path").asText());
            es.setDocumentid(jsonNode.path("documentId").asInt());
            es.setFilename(jsonNode.path("filename").asText());
            es.setLike(jsonNode.path("like").asInt());
            es.setPage(jsonNode.path("page").asInt());
            es.setClick(jsonNode.path("click").asInt());

            es.setRelativeScore(relativeScore);

            if (hit.getIndex().equals("image")) {
                es.setType("图片");
            } else {
                es.setType("文本");
            }
//            es.setType(hit.getIndex());
            es.setUserid(jsonNode.path("userid").asInt());
            es.setScore(score);
            // 解析日期字符串
//            Instant instant = Instant.parse(jsonNode.path("uploadTime").asText());
            // 解析字符串为 LocalDateTime 对象
            LocalDateTime dateTime = LocalDateTime.parse(jsonNode.path("uploadTime").asText(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);

            // 定义所需的日期时间格式
            DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");

            // 格式化日期时间为指定格式
            String output = dateTime.format(outputFormatter);
            es.setUploadTime(output);

            es.setUploadUserName(jsonNode.path("uploadUserName").asText());
            // 检查是否存在pdfText字段的高亮结果
            if (hit.getHighlightFields().containsKey("pdfText")) {
                // 获取pdfText字段的高亮片段
                Text[] pdfTextHighlights = hit.getHighlightFields().get("pdfText").getFragments();
                StringBuilder pdfTextHighlightBuilder = new StringBuilder();
                for (Text highlight : pdfTextHighlights) {
                    pdfTextHighlightBuilder.append(highlight.string());
                }
                es.setPdftext(pdfTextHighlightBuilder.toString());
            }


            // 检查是否存在ocrText字段的高亮结果
            if (hit.getHighlightFields().containsKey("ocrText")) {
                // 获取ocrText字段的高亮片段
                Text[] ocrTextHighlights = hit.getHighlightFields().get("ocrText").getFragments();
                StringBuilder ocrTextHighlightBuilder = new StringBuilder();
                for (Text highlight : ocrTextHighlights) {
                    ocrTextHighlightBuilder.append(highlight.string());
                }
                es.setPdftext(ocrTextHighlightBuilder.toString());
            }

            esMapper.insertByFilename(tableName, es);

        }

        //从mysql重新进行评分获取数据并排序
        List<Es> list = esMapper.searchByFilename(tableName, searchKey);

        //删除表
        esMapper.dropTable(tableName);
        return list;
    }


    @Override
    public void updateLike(int like, int id) {
        UpdateByQueryRequest request = new UpdateByQueryRequest("pdftxt,image");
        request.setQuery(new TermQueryBuilder("documentId", id));
        request.setScript(new Script("ctx._source['like']=" + like + ";"));
        try {
            client.updateByQuery(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void updateClick(int click, int id) {

        UpdateByQueryRequest request = new UpdateByQueryRequest("pdftxt,image");
        request.setQuery(new TermQueryBuilder("documentId", id));
        request.setScript(new Script("ctx._source['click']=" + click + ";"));
        try {
            client.updateByQuery(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public Integer starByUserId(int userId, EsStar esStar) {
        String tableName = "star_" + userId;
        if (esMapper.isExitsTable(tableName) == 0) {
            esMapper.createStarTable(tableName);
        }
//        检查是否已经收藏过该数据,存在则删除，不存在则插入
        System.out.println(esStar);
        if (esMapper.selectStarTableByData(tableName, esStar.getId(), esStar.getSearchKey()) == null) {
            esMapper.insertStarTable(tableName, esStar);
            return 1;
        } else {
            esMapper.deleteStarById(tableName, esStar.getId());
            return 0;
        }
    }

    @Override
    public List<EsStar> selectStarByUserId(int userId) {
        String tableName = "star_" + userId;
        if (esMapper.isExitsTable(tableName) == 0) {
            esMapper.createStarTable(tableName);
        }

        List<EsStar> list = esMapper.selectStarTable(tableName);
        for (int i = 0; i < list.size(); i++) {
            deleteNothingDataUserStarByDocumentId(userId, list.get(i).getDocumentid());
        }
        List<EsStar> list1 = esMapper.selectStarTable(tableName);
        return list1;
    }

    @Override
    public Integer showIsStar(int userId, int id, String searchKey) {
        String tableName = "star_" + userId;
        if (esMapper.isExitsTable(tableName) == 0) {
            esMapper.createStarTable(tableName);
        }
        if (esMapper.selectStarTableByData(tableName, id, searchKey) == null) {
            return 0;
        }
        return 1;
    }

    @Override
    public Integer deleteEsDataByDocumentId(int userId, int documentId) {
        DeleteByQueryRequest request = new DeleteByQueryRequest("pdftxt,image");
        request.setQuery(new TermQueryBuilder("documentId", documentId)).setQuery(new TermQueryBuilder("userid", userId));
        try {
            client.deleteByQuery(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return 1;
    }

    @Override
    public List<Es> searchByType(String searchKey, int userId, String type) {
        String tableName = "search_" + userId;
        if (esMapper.isExitsTable(tableName) == 0) {
            esMapper.createSearchTable(tableName);
        }

        SearchRequest searchRequest = new SearchRequest("pdftxt,image");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        MultiMatchQueryBuilder multiMatchQuery = QueryBuilders.multiMatchQuery(searchKey, "ocrText", "pdfText");

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery().must(multiMatchQuery);

        sourceBuilder.query(boolQuery);

        HighlightBuilder highlightBuilder = new HighlightBuilder()
                .field("ocrText")
                .field("pdfText")
                .preTags("<mark style='color:red'>")
                .postTags("</mark>")
                .fragmentSize(50);

        sourceBuilder.highlighter(highlightBuilder);
        //获取条数
        sourceBuilder.size(120);
        sourceBuilder.timeout(TimeValue.timeValueSeconds(10));
        //去重根据id折叠
        sourceBuilder.collapse(new CollapseBuilder("id"));
        searchRequest.source(sourceBuilder);

        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
//        System.out.println(searchResponse);


        ObjectMapper objectMapper = new ObjectMapper();


// 处理查询结果
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            Es es = new Es();
            // 获取原始文档
            String sourceAsString = hit.getSourceAsString();
//            System.out.println("Source: " + sourceAsString);

            JsonNode jsonNode = null;
            try {
                jsonNode = objectMapper.readTree(sourceAsString);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
            // 获取高亮的片段
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();


            HighlightField pdfTextHighlightField = highlightFields.get("pdfText");
            HighlightField ocrTextHighlightField = highlightFields.get("ocrText");

            //计算最终评分
            DecimalFormat df = new DecimalFormat();
            df.setMinimumFractionDigits(1);
            int like = jsonNode.path("like").asInt();
            int click = jsonNode.path("click").asInt();
            float oldRelativeScore = hit.getScore();
            float relativeScore = Float.parseFloat(df.format(oldRelativeScore));

            double oldScore = relativeScore * 0.6 + like * 0.3 + click * 0.1;
            float score = Float.parseFloat((df.format(oldScore)));

            //检查该数据是否已收藏
            es.setStar(showIsStar(userId, jsonNode.path("id").asInt(), searchKey));

            //注入到对象
            es.setId(jsonNode.path("id").asInt());
//            es.setPath(jsonNode.path("path").asText());
            es.setDocumentid(jsonNode.path("documentId").asInt());
            es.setFilename(jsonNode.path("filename").asText());
            es.setLike(jsonNode.path("like").asInt());
            es.setPage(jsonNode.path("page").asInt());
            es.setClick(jsonNode.path("click").asInt());

            es.setRelativeScore(relativeScore);

            if (hit.getIndex().equals("image")) {
                es.setType("图片");
            } else {
                es.setType("文本");
            }
//            es.setType(hit.getIndex());
            es.setUserid(jsonNode.path("userid").asInt());
            es.setScore(score);
            // 解析日期字符串
//            Instant instant = Instant.parse(jsonNode.path("uploadTime").asText());
            // 解析字符串为 LocalDateTime 对象
            LocalDateTime dateTime = LocalDateTime.parse(jsonNode.path("uploadTime").asText(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);

            // 定义所需的日期时间格式
            DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");

            // 格式化日期时间为指定格式
            String output = dateTime.format(outputFormatter);
            es.setUploadTime(output);

            es.setUploadUserName(jsonNode.path("uploadUserName").asText());
            // 检查是否存在pdfText字段的高亮结果
            if (hit.getHighlightFields().containsKey("pdfText")) {
                // 获取pdfText字段的高亮片段
                Text[] pdfTextHighlights = hit.getHighlightFields().get("pdfText").getFragments();
                StringBuilder pdfTextHighlightBuilder = new StringBuilder();
                for (Text highlight : pdfTextHighlights) {
                    pdfTextHighlightBuilder.append(highlight.string());
                }
                es.setPdftext(pdfTextHighlightBuilder.toString());
            }


            // 检查是否存在ocrText字段的高亮结果
            if (hit.getHighlightFields().containsKey("ocrText")) {
                // 获取ocrText字段的高亮片段
                Text[] ocrTextHighlights = hit.getHighlightFields().get("ocrText").getFragments();
                StringBuilder ocrTextHighlightBuilder = new StringBuilder();
                for (Text highlight : ocrTextHighlights) {
                    ocrTextHighlightBuilder.append(highlight.string());
                }
                es.setPdftext(ocrTextHighlightBuilder.toString());
            }

            esMapper.insertByFilename(tableName, es);

        }


        List<Es> list = new ArrayList<>();
        //从mysql重新进行评分获取数据并排序
        if (type.equals("图片")) {
//            System.out.println("图片");
            list = esMapper.searchByFilenameImage(tableName, searchKey);
        } else {
//            System.out.println("文本");
            list = esMapper.searchByFilenamePdfText(tableName, searchKey);
        }


        //删除表
        esMapper.dropTable(tableName);
        return list;
    }

    @Override
    public Integer deleteNothingDataUserStarByDocumentId(int userId, int documentId) {
        String tableName = "star_" + userId;
        if (esMapper.isExitsTable(tableName) == 0) {
            esMapper.createStarTable(tableName);
        }
        if (fileMapper.findByDocId(userId, documentId) == null) {
            if (esMapper.selectStarAndDocumentidTableByData(tableName, documentId) != null) {
                esMapper.deleteStarByDocumentid(tableName, documentId);

            }
        }
        return 1;

    }
}






